﻿using System;
using System.Collections.Generic;

namespace 密封类和抽象类
{
    class Program
    {
        static void Main(string[] args)
        {
            // sealed ：密封，只能写在重写的方法上，常规方法会报错
            //public sealed void Eat(){        }
            // sealed 用于修饰 重写的方法，表示子类不能再重写（override 修饰的方法）
            // 表示一个能力的退化(阉割)，在此处表示吃饭的能力在子类中退化了
            //不可以用抽象类来进行实例化，但可以用抽象类来声明

            // Student stu = new Student();抽象类不可以创建实例，但是可以借用里氏转换父类指向子类指针
            Student stu = new 大学生();
           int a = stu.Sing($"我也是大学生");
            stu.Eat();
            Console.WriteLine(a);
            大学生 da = new 大学生();
            da.Sing("我爷爷是大学生");
            
        }
    }
    /// <summary>
    /// 动物
    /// </summary>
    class Animal
    {
        public virtual void Eat()
        {
            Console.WriteLine("我可以吃");
        }
    }
    class Person : Animal//Person 人类 
    {
        public sealed override void Eat()//sealede 密封 不许别的子类重写这个方法了
        {
            base.Eat();
            Console.WriteLine("除了我没人可以吃了");
        }
    }
    /// <summary>
    /// 未来人类
    /// </summary>
    class FuturePerson : Person//Future：未来
    {
      //public override void Eat()//IDE会报错，提醒你这是一个密封类不可以重写了
      //  {

      //  }
    }

    /// <summary>
    /// 机器人
    /// </summary>
    // sealed 修饰类类型时，表示该 类 不能被继承，但是密封的类可以继承别人
    // 用于 已经明确知道不可能存在继承关系的类类型中,比如帮助类，管理类
    // 告诉别人（也代表未来的你）遵守你的规则的一种强制性的措施。
    sealed class Robot:FuturePerson
    {
        public void Say(string msg)
        {
            /// <summary>
            /// 机器人说话的能力
            /// <br>msg = message :消息</br>
            /// </summary>
            /// <param name="msg">要表达的消息，句子</param>
            Console.WriteLine($"机器人会说话{msg}");
        }
    }
    // class Dog : Robot { } 无法从密封类 Robot 继承

    //当父类中的方法不知道如何去实现的时候，可以考虑将父类写成抽象类，将方法写成抽象方法。
    // abstract  抽象，提取本质的共通的特性
    // abstract 修饰的方法不能有实体，也就是不能有方法的具体实现
    // abstract  修饰的类类型成员（方法、属性）必须存在于 abstract 修饰的类类型种。
    // student :学生，学生本质上正在学习某一个技能中的生物个体。
    // abstract 下修饰的 student 有意义
    // abstract 对 class  ，function （方法），属性修饰，字段却不行
    // abstract 修饰的类类型中的成员不一定需要用 abstract 修饰
    // 所有继承自该类的子类都必须实现该类中的所有抽象函数，抽象字段。
    // 在抽象类中可以包含实例成员，并且抽象类的实例成员可以不被子类实例。
     //如果父类的抽象方法中有参数，那么，继承这个抽象父类的子类在重写父类的方法的时候必须传入对应的参数
     //如果抽象父类的抽象方法中有返回值，那么子类在重写这个抽象方法的时候，也必须要传入返回值
    abstract class Student//学生
    {
        //public abstract string name;不可以抽象字段
        public abstract string Name { get; set;}//使用自动属性不去进行判断的话，这个属性就相当于一个普通的字段
        //sing:唱歌
        public abstract int Sing(string a);//抽象方法不可以有主体。
        /*string a = "";
         索引器的常规写法 
        public string this[int index]
        {
            get { return a; }
            set { a = value; }
        }*/
        public abstract string this[int index] { get;set; }//抽象的索引器

        public void Eat()//抽象类中可以包含实例成员，继承的子类中因为没有标记抽象类所以不需要重写
        {
            Console.WriteLine("我可以吃");
        }
    }
    //抽象类如果被继承必须100%实现抽象成员
    class 大学生 : Student
    {
        string a = "大学生";
        List<string> books = new List<string>();
        public override string this[int index] { get => books[index]; set => books[index]=value; }

        public override string Name { get { return a; } set { a = value; }}
        
        public override int Sing(string a)
        {
            int c = 10;
            int cc = 20;
            
            Console.WriteLine($"{Name}能唱歌{a}");
            return c += cc;
        }
        //public override void Eat()因为父类没有标记abstract所以子类无法重写
        //{

        //}
    }
}
